﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.Util;
using System.Collections;
using Emgu.CV.UI;
namespace emguCVTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        string winname = "First Window";
        private void button1_Click(object sender, EventArgs e)
        {
            CvInvoke.NamedWindow(winname);
            Mat img = new Mat(200, 400, DepthType.Cv8U, 3);
            img.SetTo(new Bgr(255, 0, 0).MCvScalar);
            CvInvoke.PutText(img, "Hello World", new System.Drawing.Point(10, 80), FontFace.HersheyComplex, 1.0, new Bgr(0, 255, 0).MCvScalar);
            CvInvoke.Imshow(winname, img);
            CvInvoke.WaitKey(0);
            CvInvoke.DestroyWindow(winname);
        }
        Mat image=new Mat();
        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog OpenFile = new OpenFileDialog();
            if(OpenFile.ShowDialog()==DialogResult.OK)
            {
                Image<Bgr, Byte> myImg = new Image<Bgr, byte>(OpenFile.FileName);
                pictureBox1.Image = myImg.ToBitmap();

                image = CvInvoke.Imread(OpenFile.FileName,LoadImageType.AnyColor|LoadImageType.AnyDepth);
                if(image.IsEmpty)
                {
                    textBox1.Text = "No Image loaded.";
                    return;
                }
                
                imageBox1.Image = image;
                textBox1.Text = image.Rows + "*" + image.Cols+"*"+image.NumberOfChannels+"\n";
                
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if(!image.IsEmpty)
            {
                Mat result=image.Clone();
                
                CvInvoke.Flip(image, result, FlipType.Horizontal);
                CvInvoke.PutText(result, "ha ha ha~",new Point(result.Width / 2, result.Height / 2), FontFace.HersheyPlain, 2.0, new MCvScalar(256,128,0), 2);
                CvInvoke.Imshow("Flip", result);
            }
        }

        private void CreateButton_Click(object sender, EventArgs e)
        {
            Image<Bgr, byte> img1 = new Image<Bgr, byte>(pictureBox2.Width, pictureBox2.Height, new Bgr(255, 0, 0));
            pictureBox2.Image = img1.ToBitmap();
        }

        private void buttonOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if(ofd.ShowDialog()==DialogResult.OK)
            {
                var img = new Image<Bgr, byte>(ofd.FileName);
                pictureBox2.Image = img.ToBitmap();
            }
        }

        private void buttonSetPixels_Click(object sender, EventArgs e)
        {
            var img1 = new Image<Bgr, byte>(pictureBox2.Width, pictureBox2.Height, new Bgr(255, 0, 0));
            for(int i=20;i<60;++i)
                for(int j=20;j<60;++j)
                {
                    img1[i, j] = new Bgr(0, 255, 255);
                }
            for(int i=120;i<160;++i)
                for(int j=20;j<60;++j)
                {
                    img1.Data[i, j, 0] = 0;
                    img1.Data[i, j, 1] = 255;
                    img1.Data[i, j, 2] = 255;
                }
            var data = img1.Data;
            for(int i=20;i<60;++i)
                for(int j=100;j<140;++j)
                {
                    data[i, j, 0] = 0;
                    data[i, j, 1] = 255;
                    data[i, j, 2] = 255;
                }
            pictureBox2.Image = img1.ToBitmap();
        }

        private void buttonBGR_Click(object sender, EventArgs e)
        {
            var img = new Image<Bgr, byte>(pictureBox2.Width, pictureBox2.Height, new Bgr(255, 0, 0));
            var img2 = new Image<Bgr, byte>(pictureBox2.Width, pictureBox2.Height, new Bgr(0, 125, 0));
            var img3 = new Image<Bgr, byte>(pictureBox2.Width, pictureBox2.Height, new Bgr(0, 0, 255));
            var img4 = img + img2 + img3;
            pictureBox2.Image = img4.ToBitmap();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            var mat1 = new Matrix<double>(5, 7);
            matrixBox1.Matrix = mat1;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            double element = 0;
            var mat = new Matrix<double>(5, 7);
            for(int i=0;i<mat.Rows;i++)
                for(int j=0;j<mat.Cols;j++)
                {
                    mat.Data[i, j] = element++;
                }
            matrixBox1.Matrix = mat;
        }
        Image<Bgr, Byte> imgForEmguCVChapter7;
        private void button6_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if(ofd.ShowDialog()==DialogResult.OK)
            {
                imgForEmguCVChapter7 = new Image<Bgr, byte>(ofd.FileName);
                pictureBox3.Image = imgForEmguCVChapter7.ToBitmap();
                
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            
            var img = imgForEmguCVChapter7.Convert<Gray, byte>().PyrDown().PyrUp();
            var imgCanny = img.Canny(120, 180);
            pictureBox4.Image = imgCanny.ToBitmap();
        }

        private void button8_Click(object sender, EventArgs e)
        {
            var cannyGray = new Image<Gray, byte>(new Bitmap(pictureBox4.Image));
            LineSegment2D[] lines = cannyGray.HoughLinesBinary(1, Math.PI / 45, 20, 30, 10)[0];
            var imgs = new Image<Bgr, byte>(cannyGray.Width, cannyGray.Height);
            foreach(LineSegment2D line in lines)
            {
                imgs.Draw(line, new Bgr(Color.DeepPink), 5);
                
            }
            pictureBox4.Image = imgs.ToBitmap();
        }
        Mat function1_4()
        {
            Mat ima=new Mat(500, 500, DepthType.Cv8U, 50);
            ima.SetTo(new MCvScalar(50));
            return ima;
        }
        private void button11_Click(object sender, EventArgs e)
        {
            Mat img1 = new Mat(240, 320, DepthType.Cv8U,1);
            img1.SetTo(new MCvScalar(100));
            CvInvoke.Imshow("Image", img1);
            CvInvoke.WaitKey(0);
            img1.Create(400, 400, DepthType.Cv8U, 1);
            img1.SetTo(new MCvScalar(111));
            CvInvoke.Imshow("Image", img1);
            CvInvoke.WaitKey(0);
            img1.Create(240, 240, DepthType.Cv8U, 3);
            img1.SetTo(new MCvScalar(0, 0, 255));
            CvInvoke.Imshow("Image", img1);
            CvInvoke.WaitKey(0);
            if (image.IsEmpty)
                return;
            var img2 = image;
            var img3 = img2;
            var img4 = new Mat(img3.Size, img3.Depth, img3.NumberOfChannels);
            img3.CopyTo(img4);
            var img5 = img3.Clone();
            CvInvoke.DestroyAllWindows();
            CvInvoke.Flip(img2, img2, FlipType.Horizontal);
            CvInvoke.Imshow("image", image);
            CvInvoke.Imshow("img2", img2);
            CvInvoke.Imshow("img3", img3);
            CvInvoke.Imshow("img4", img4);
            CvInvoke.Imshow("img5", img5);
        }
        Mat maskImage=new Mat();
        private void button12_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
                maskImage = CvInvoke.Imread(ofd.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            if (maskImage.IsEmpty | image.IsEmpty)
                return;
            pictureBox5.Image = maskImage.ToImage<Bgr,byte>().ToBitmap();
            Mat imageROI = new Mat(image, new Rectangle(image.Cols - maskImage.Cols, image.Rows - maskImage.Rows, maskImage.Cols, maskImage.Rows));
            maskImage.CopyTo(imageROI);
            imageBox1.Image=image;
            CvInvoke.NamedWindow("mask", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("mask", image);
        }

        private void button13_Click(object sender, EventArgs e)
        {
            if (image.IsEmpty | maskImage.IsEmpty)
                return;
            OpenFileDialog ofd = new OpenFileDialog();
            Mat img=new Mat();
            if(ofd.ShowDialog()==DialogResult.OK)
            {
                img = CvInvoke.Imread(ofd.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            }
            if (img.IsEmpty)
                return;
            var imageROI = new Mat(img, new Rectangle(img.Cols - maskImage.Cols, img.Rows - maskImage.Rows, maskImage.Cols, maskImage.Rows));
            var imageROIMask = new Mat(maskImage.Size, DepthType.Cv8U, 1); ;
            CvInvoke.CvtColor(maskImage, imageROIMask, ColorConversion.Bgr2Gray);
            CvInvoke.Threshold(imageROIMask, imageROIMask, 200, 255, ThresholdType.Binary);
            CvInvoke.Imshow("Mask", imageROIMask);
            CvInvoke.WaitKey(0);
            maskImage.CopyTo(imageROI);
            CvInvoke.NamedWindow("insertMask", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("insertMask", img);
        }

        Mat chapter1Image = new Mat();
        Mat chapter1Mask = new Mat();
        Mat chapter1GrayMask = new Mat();
        OpenFileDialog chapter1OFD = new OpenFileDialog();
        private void button14_Click(object sender, EventArgs e)
        {
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                chapter1Image = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            if (chapter1Image.IsEmpty)
                return;
            imageBox2.Image = chapter1Image;
        }

        private void button15_Click(object sender, EventArgs e)
        {
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                chapter1Mask = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            if (!chapter1Mask.IsEmpty)
                imageBox3.Image = chapter1Mask;
        }

        private void button16_Click(object sender, EventArgs e)
        {
            if (chapter1Mask.IsEmpty)
                return;
            chapter1GrayMask = new Mat(chapter1Mask.Size, chapter1Mask.Depth, 1);
            CvInvoke.CvtColor(chapter1Mask, chapter1GrayMask, ColorConversion.Bgr2Gray, 1);
            if (!chapter1GrayMask.IsEmpty)
                imageBox4.Image = chapter1GrayMask;
        }

        private void button17_Click(object sender, EventArgs e)
        {
            if (chapter1GrayMask.IsEmpty | chapter1Image.IsEmpty)
                return; 
            Mat mask = new Mat(chapter1Image.Size, DepthType.Cv8U, 1);
            Mat roi = new Mat(mask, new Rectangle(chapter1Image.Cols - chapter1GrayMask.Cols, chapter1Image.Rows - chapter1GrayMask.Rows, chapter1GrayMask.Cols, chapter1GrayMask.Rows));
            roi.SetTo(new MCvScalar(255));
            imageBox4.Image = mask;
            Mat result = new Mat();
            chapter1Image.CopyTo(result, mask);
            imageBox5.Image = result;
        }

        Mat chapter2Img = new Mat();
        Image<Bgr, byte> chapter2ImgBGR;
        Image<Gray, byte> chapter2ImgGray;
        private bool chapter2SaultNoise(Mat inImg,int n)
        {
            int i, j;
            Random rd = new Random();
            IntPtr ip = inImg.Ptr;
            
            for(int k=0;k< n;++k)
            {
                i = rd.Next(0, inImg.Rows);
                j = rd.Next(0, inImg.Cols);
                if(inImg.NumberOfChannels==1)
                {
                    chapter2ImgGray[i, j] = new Gray(0);
                }
                else if(inImg.NumberOfChannels==3)
                {
                    chapter2ImgBGR[i, j] = new Bgr(0, 0, 0);
                }else
                {
                    return false;
                }
            }
            if (inImg.NumberOfChannels == 1)
            {
                chapter2ImgGray.Mat.CopyTo(inImg);
            }
            else if (inImg.NumberOfChannels == 3)
            {
                chapter2ImgBGR.Mat.CopyTo(inImg);
            }
            return true;
        }
        private void button18_Click(object sender, EventArgs e)
        {
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                chapter2Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            else
                return;
            imageBox6.Image = chapter2Img;
            if(chapter2Img.NumberOfChannels==1)
            {
                chapter2ImgGray = chapter2Img.ToImage<Gray,byte>();
            }else if(chapter2Img.NumberOfChannels==3)
            {
                chapter2ImgBGR = chapter2Img.ToImage<Bgr, byte>();
            }
        }
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        private void button19_Click(object sender, EventArgs e)
        {
            
            if (chapter2Img.IsEmpty)
                return;
            if (!chapter2SaultNoise(chapter2Img, chapter2Img.Cols* chapter2Img.Rows/10))
                return;
            imageBox6.Image = chapter2Img;
        }
        /// <summary>
        /// 将图像位数减小，系数为div
        /// 此处假设图像为8位RGB图像，减少代码量
        /// </summary>
        /// <param name="inImg"></param>
        /// <param name="div"></param>
        /// <returns></returns>
        private bool chapter2ColorReduce(Mat inImg,int div=64)
        {
            int nc = inImg.Cols;
            int nr = inImg.Rows;
            if (inImg.IsEmpty)
                return false;
            Image<Bgr, byte> tempImg = inImg.ToImage<Bgr, byte>();
            sw.Start();
            for(int i=0;i<nr;++i)
                for(int j=0;j<nc;++j)
                {
                    tempImg.Data[i, j, 0] = (byte)(tempImg.Data[i, j, 0] / div * div + div / 2);
                    tempImg.Data[i, j, 2] = (byte)(tempImg.Data[i, j, 2] / div * div + div / 2);
                }
            sw.Stop();
            textBox2.Text = sw.ElapsedMilliseconds.ToString();
            tempImg.Mat.CopyTo(inImg);
            return true;
        }
        private void button21_Click(object sender, EventArgs e)
        {
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                chapter2Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            if (chapter2Img.IsEmpty)
                return;
            imageBox7.Image = chapter2Img;

        }

        private void button20_Click(object sender, EventArgs e)
        {
            var tempImg = chapter2Img.Clone();
            if (!chapter2ColorReduce(tempImg,(int)numericUpDown1.Value))
                return;
            imageBox7.Image = tempImg;
        }

        private void button22_Click(object sender, EventArgs e)
        {
            if (chapter2Img.IsEmpty)
                return;
            var tempImg = chapter2Img.ToImage<Bgr, byte>();
            unsafe
            {
                int nr = tempImg.Rows;
                int ncol = tempImg.Cols;
                int nc = tempImg.NumberOfChannels;
                int stride = tempImg.MIplImage.WidthStep;
                byte* data = (byte*)tempImg.MIplImage.ImageData;
                int div = (int)numericUpDown1.Value;
                sw.Start();
                for (int i=0;i<nr;++i)
                {
                    for(int j=0;j< stride; ++j)
                    {
                        data[j] = (byte)(data[j] / div * div + div / 2);
                    }
                    data += stride;
                }
                sw.Stop();
                textBox2.Text += "\n"+sw.ElapsedMilliseconds.ToString();
            }
            imageBox7.Image = tempImg;
        }
        //此部分代码功能是锐化图像，本质上是 扫描图像并访问相邻像素
        //sharpened_pixel=5*current-left-right-up-down
        byte saturateCast(double inValue)
        {
            if (inValue < 0)
                return 0;
            else if (inValue > 255)
                return 255;
            else
                return (byte)inValue;
        }
        bool sharpen(Mat inImg,Mat outImg)
        {
            int nchannel = inImg.NumberOfChannels;
            int nrows = inImg.Rows;
            int ncols = inImg.Cols;
            if(nchannel==1)
            {
                var tempImg=inImg.ToImage<Gray,byte>();
                var tempImg2 = tempImg.Clone();
                for(int i=1;i<nrows-1;++i)
                {
                    for(int j=1;j<ncols-1;++j)
                    {
                        tempImg2.Data[i, j, 0] = saturateCast(5 * tempImg.Data[i, j, 0] - tempImg.Data[i - 1, j, 0] - tempImg.Data[i, j - 1, 0] -
                        tempImg2.Data[i + 1, j, 0] - tempImg.Data[i, j + 1, 0]);
                    }
                }
                for(int i=0;i<nrows;++i)
                {
                    tempImg2.Data[i, 0, 0] = 0;
                    tempImg2.Data[i, ncols - 1, 0] = 0;
                }
                for(int j=0;j<ncols;++j)
                {
                    tempImg2.Data[0, j, 0] = 0;
                    tempImg2.Data[nrows - 1, j, 0] = 0;
                }
                tempImg2.Mat.CopyTo(outImg);
            }
            else if(nchannel==3)
            {
                var tempImg = inImg.ToImage<Bgr, byte>();
                var tempImg2 = tempImg.Clone();
                for(int i=1;i<nrows-1;++i)
                {
                    for(int j=1;j<ncols-1;++j)
                    {
                        for(int channel=0;channel<3;channel++)
                        {
                            tempImg2.Data[i, j, channel] = saturateCast(5 * tempImg.Data[i, j, channel] - tempImg.Data[i - 1, j, channel] - tempImg.Data[i, j - 1, channel] -
                                tempImg.Data[i + 1, j, channel] - tempImg.Data[i, j + 1, channel]);
                        }
                    }
                }
                for(int i=0;i<nrows;++i)
                {
                    for(int channel=0;channel<3;channel++)
                    {
                        tempImg2.Data[i, 0, channel] = 0;
                        tempImg2.Data[i, ncols - 1, channel] = 0;
                    }
                }
                for(int j=0;j<ncols;++j)
                {
                    for(int channel=0;channel<3;channel++)
                    {
                        tempImg2.Data[0, j, channel] = 0;
                        tempImg2.Data[nrows - 1, j, channel] = 0;
                    }
                }
                tempImg2.Mat.CopyTo(outImg);
            }else
            {
                return false;
            }
            return true;
        }
        private void button27_Click(object sender, EventArgs e)
        {
            Mat inImage = new Mat();
            Mat outImage = new Mat();
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                inImage = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            if (inImage.IsEmpty)
                return;
            if (!sharpen(inImage, outImage))
                return;
            if (outImage.IsEmpty)
                return;
            imageBox7.Image = outImage;
        }
        private void button28_Click(object sender, EventArgs e)
        {
            if (chapter2Img.IsEmpty)
                return;
            Image<Gray, float> kernelI = new Image<Gray, float>(3, 3, new Gray(0));
            kernelI.Data[1, 1, 0] = (float)5.0;
            kernelI.Data[0, 1, 0] = (float)-1.0;
            kernelI.Data[1, 0, 0] = (float)-1.0;
            kernelI.Data[2, 1, 0] = (float)-1.0;
            kernelI.Data[1, 2, 0] = (float)-1.0;
            if(chapter2Img.NumberOfChannels==3)
            {
                var tempImg = chapter2Img.ToImage<Bgr, byte>();
                Image<Gray,byte>[] results = tempImg.Split();
                CvInvoke.Filter2D(results[0].Mat, results[0].Mat, kernelI.Mat, new Point(-1, -1));
                CvInvoke.Filter2D(results[1].Mat, results[1].Mat, kernelI.Mat, new Point(-1, -1));
                CvInvoke.Filter2D(results[2].Mat, results[2].Mat, kernelI.Mat, new Point(-1, -1));
                
                for(int i=0;i<tempImg.Rows;i++)
                    for(int j=0;j<tempImg.Cols;j++)
                    {
                        tempImg.Data[i, j, 0] = results[0].Data[i, j, 0];
                        tempImg.Data[i, j, 1] = results[1].Data[i, j, 0];
                        tempImg.Data[i, j, 2] = results[2].Data[i, j, 0];
                    }
                imageBox7.Image = tempImg;
            }
            else if(chapter2Img.NumberOfChannels==1)
            {
                var tempImg = chapter2Img.ToImage<Gray, byte>();
                CvInvoke.Filter2D(tempImg.Mat, tempImg.Mat, kernelI.Mat, new Point(-1, -1));
                imageBox7.Image = tempImg;
            }
        }
        //以下为chapter3
        Mat chapter3Img = new Mat();
        private void button29_Click(object sender, EventArgs e)
        {
            if(chapter1OFD.ShowDialog()==DialogResult.OK)
            {
                chapter3Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
                if (chapter3Img.IsEmpty)
                    return;
            }
            imageBox11.Image = chapter3Img;
        }
        private void button30_Click(object sender, EventArgs e)
        {
            if (chapter3Img.IsEmpty)
                return;
            ColorDetector cd = new ColorDetector();
            cd.setTargetColor(230, 190, 130);
            var result = cd.process(chapter3Img);
            CvInvoke.NamedWindow("result", NamedWindowType.Normal);
            CvInvoke.Imshow("result", result);
        }
        //HSV分解
        private void button31_Click(object sender, EventArgs e)
        {
            if (chapter3Img.IsEmpty)
                return;
            var tempImg = new Mat();
            CvInvoke.CvtColor(chapter3Img, tempImg, ColorConversion.Bgr2Hsv);
            if (tempImg.IsEmpty)
                return;
            var imgs = tempImg.Split();
            imageBox12.Image = imgs[2];
            imageBox14.Image = imgs[1];
            imageBox13.Image = imgs[0];
        }

        private void button32_Click(object sender, EventArgs e)
        {
            if (chapter3Img.IsEmpty)
                return;
            var tempImg = new Mat();
            CvInvoke.CvtColor(chapter3Img, tempImg, ColorConversion.Bgr2Hsv);
            if (tempImg.IsEmpty)
                return;
            //var imgs = tempImg.Split();
            //imgs[2].SetTo(new MCvScalar(255));
            var img = tempImg.ToImage<Hsv, byte>();
            for(int i=0;i<img.Rows;i++)
                for(int j=0;j<img.Cols;j++)
                {
                    img.Data[i, j, 2] = 255;
                }
            CvInvoke.CvtColor(img.Mat, tempImg, ColorConversion.Hsv2Bgr);
            imageBox15.Image = tempImg;
        }
        //基于HSV彩色空间的皮肤识别
        void detectHScolor(Mat inImg,double minHue,double maxHue,double minSat,double maxSat,out Mat mask)
        {
            Mat HSVImg=new Mat();
            CvInvoke.CvtColor(inImg, HSVImg, ColorConversion.Bgr2Hsv);
            var hsvImgs = HSVImg.ToImage<Hsv, byte>().Split();
            //色调掩码
            Mat mask1 = new Mat();//小于maxHue
            CvInvoke.Threshold(hsvImgs[0], mask1, maxHue, 255,ThresholdType.BinaryInv);
            Mat mask2 = new Mat();//大于minHue
            CvInvoke.Threshold(hsvImgs[0], mask2, minHue, 255, ThresholdType.Binary);
            Mat hueMask = new Mat();//色调掩码
            if (minHue < maxHue)
                CvInvoke.BitwiseAnd(mask1, mask2, hueMask);
            else
                CvInvoke.BitwiseOr(mask1, mask2, hueMask);
            //饱和度掩码
            CvInvoke.Threshold(hsvImgs[1], mask1, maxSat, 255, ThresholdType.BinaryInv);
            CvInvoke.Threshold(hsvImgs[1], mask2, minSat, 255, ThresholdType.Binary);
            Mat satMask = new Mat();//饱和度掩码
            CvInvoke.BitwiseAnd(mask1, mask2, satMask);
            mask = new Mat();
            CvInvoke.BitwiseAnd(hueMask, satMask, mask);
            CvInvoke.NamedWindow("hue", NamedWindowType.Normal);
            CvInvoke.NamedWindow("sat", NamedWindowType.Normal);
            CvInvoke.Imshow("hue", hueMask);
            CvInvoke.Imshow("sat", satMask);
        }
        private void button33_Click(object sender, EventArgs e)
        {
            if (chapter3Img.IsEmpty)
                return;
            Mat resultImg = new Mat();
            detectHScolor(chapter3Img, 160, 10, 25, 166, out resultImg);
            Mat detectedImg = chapter3Img.Clone();
            detectedImg.SetTo(new MCvScalar(0, 0, 0));
            chapter3Img.CopyTo(detectedImg, resultImg);
            imageBox16.Image = detectedImg;
        }
        Mat chapter4Img = new Mat();
        private void button34_Click(object sender, EventArgs e)
        {
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                chapter4Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
            if (chapter4Img.IsEmpty)
                return;
            imageBox17.Image = chapter4Img;
        }
        //以下是直方图计算类（灰度图像）,内部使用DenseHistogram类
        class HisttoGram1D
        {
            private int[] channels=new int[1];//使用的通道index
            private int[] histSize= new int[1];//bin数量
            private RangeF[] ranges=new RangeF[1];//像素值范围
            private Mat mask=new Mat();//掩码
            private Mat hist=new Mat();//得到的直方图数据
            public HisttoGram1D()
            {
                channels[0] = 0;
                histSize[0] = 256;
                ranges[0] = new RangeF(0.0f, 255.1f);
            }
            public DenseHistogram getDenseHistogram(Mat inImg)
            {
                if (inImg.IsEmpty)
                {
                    return null;
                }
                DenseHistogram dh = new DenseHistogram(histSize, ranges);
                var imgs = inImg.ToImage<Gray, byte>().Split();
                dh.Calculate(imgs, false, null);//计算直方图信息
                return dh;
            }
        }
        //直方图类定义over
        private void button35_Click(object sender, EventArgs e)//单通道图像
        {
            Mat tempImg = new Mat();
            HisttoGram1D ht1D = new HisttoGram1D();
            if (chapter4Img.NumberOfChannels != 1)
            {
                CvInvoke.CvtColor(chapter4Img, tempImg, ColorConversion.Bgr2Gray);//彩色转灰度
            }
            else
            {
                tempImg = chapter4Img.Clone();
            }
            if (tempImg.IsEmpty)
                return;
            imageBox17.Image = tempImg;
            //以下采用HistogramViewer类直接显示图像直方图
            HistogramViewer hv = new HistogramViewer();
            hv.Text = "单通道直方图";
            hv.ShowInTaskbar = true;
            hv.HistogramCtrl.GenerateHistograms(tempImg, 256);
            hv.WindowState = FormWindowState.Normal;
            hv.Show();
            hv.Refresh();
            //还有一种方式，直接使用HistogramViewer的静态函数，HistogramViewer.show(tempImg,256);也可以
            
            //以下使用HistogramBox控件进行直方图显示,需要配合DenseHistogram类
            var dhData = ht1D.getDenseHistogram(tempImg);//获取DenseHistogram对象
            //值得注意的是，此时dhData，也就是DenseHistogram类，虽然是继承的Mat类，但里面存储的已经是直方图信息
            histogramBox2.ClearHistogram();
            histogramBox2.AddHistogram("HistogramBox控件显示单通道直方图", Color.FromArgb(255, 0, 0), dhData, 256, new float[] { 0.0f, 255.0f });
            histogramBox2.Refresh();

            int[] testt = new int[256];
            var ttt = tempImg.ToImage<Gray, byte>();
            for(int i=0;i<tempImg.Rows;i++)
                for(int j=0;j<tempImg.Cols;j++)
                {
                    testt[ttt.Data[i, j, 0]]++;
                }
            int ii = 0;
            for(int i=0;i<testt.Length;i++)
            {
                ii += testt[i];
            }
            double iii = 0.0;
            for(int i=0;i<dhData.GetBinValues().Length;i++)
            {
                iii += dhData.GetBinValues()[i];
            }
            int iiii = 0;
        }

        //定义函数，输入Mat图像，输出DenseHistogram对象
        DenseHistogram[] getDenseHistogramDataOfImage(Mat inImg)//这里的inImg深度暂定为byte
        {

            DenseHistogram[] dh = new DenseHistogram[3] { new DenseHistogram(256, new RangeF(0f, 255.1f)), new DenseHistogram(256, new RangeF(0f, 255.1f)), new DenseHistogram(256, new RangeF(0f, 255.1f)) };
            if (inImg.NumberOfChannels==3)
            {
                dh[0].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[0] }, false, null);
                dh[1].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[1] }, false, null);
                dh[2].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[2] }, false, null);
            }
            else
            {
                dh[0].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Gray, byte>()[0] }, false, null);
                dh[1] = null;
                dh[2] = null;
            }
            return dh;
        }
        
        private void button36_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            var dhData = getDenseHistogramDataOfImage(chapter4Img);
            histogramBox2.ClearHistogram();
            if(chapter4Img.NumberOfChannels==3)
            {
                histogramBox2.AddHistogram("Blue直方图", Color.FromArgb(0, 0, 255), dhData[0], 256, new float[] { 0.0f, 255.0f });
                histogramBox2.AddHistogram("Green直方图", Color.FromArgb(0, 255, 0), dhData[1], 256, new float[] { 0.0f, 255.0f });
                histogramBox2.AddHistogram("Red直方图", Color.FromArgb(255, 0, 0), dhData[2], 256, new float[] { 0.0f, 255.0f });
            }
            else
            {
                histogramBox2.AddHistogram("直方图", Color.FromArgb(0, 0, 0), dhData[0], 256, new float[] { 0.0f, 255.0f });
            }
            histogramBox2.Refresh();
        }
        private Mat AddMultiHistograms(DenseHistogram[] dh)//此函数功能实现由输入的直方图数据生成Mat图像
        {
            double maxValue = 0;
            double minValue = 0;
            if (dh[1] == null)//说明用于计算直方图的图像为单通道
            {
                var arrayData = dh[0].GetBinValues();
                maxValue = arrayData.Max();
                minValue = arrayData.Min();
                for (int i = 0; i < arrayData.Length; i++)
                {
                    arrayData[i] = (int)((arrayData[i] - minValue) / (maxValue - minValue) * 400.0);
                }
                var hist = new Image<Gray, byte>(512, 512, new Gray(255));
                Point p1 = new Point();
                Point p2 = new Point();
                p1.X = 0;
                p1.Y = 512-(int)arrayData[0];
                for (int i = 1; i < arrayData.Length; i++)
                {
                    p2.X = i*2;
                    p2.Y = 512-(int)arrayData[i];
                    CvInvoke.Line(hist, p1, p2, new MCvScalar(0),3);
                    p1.X = p2.X;
                    p1.Y = p2.Y;
                }
                return hist.Mat;
            }
            else
            {
                List<float[]> arrayData = new List<float[]> { dh[0].GetBinValues(), dh[1].GetBinValues(), dh[2].GetBinValues() };//颜色顺序BGR
                maxValue = Math.Max(Math.Max(dh[0].GetBinValues().Max(), dh[1].GetBinValues().Max()), dh[2].GetBinValues().Max());
                minValue=Math.Min(Math.Min(dh[0].GetBinValues().Min(), dh[1].GetBinValues().Min()), dh[2].GetBinValues().Min());
                for(int index=0;index<arrayData.Count;index++)
                {
                    for(int i=0;i<arrayData[index].Length;i++)
                    {
                        arrayData[index][i] = (float)((arrayData[index][i] - minValue) / (maxValue - minValue)*400.0);
                    }
                }
                var hist = new Image<Bgr, byte>(512, 512, new Bgr(255, 255, 255));//初始化图像
                Point p1 = new Point();
                Point p2 = new Point();
                var colors = new MCvScalar[3] { new MCvScalar(255, 0, 0), new MCvScalar(0, 255, 0), new MCvScalar(0, 0, 255) };
                for(int index=0;index<arrayData.Count;index++)
                {
                    p1.X = 0;
                    p1.Y = 512 - (int)arrayData[index][0];
                    for(int i=1;i<arrayData[index].Length;i++)
                    {
                        p2.X = i*2;
                        p2.Y = 512 - (int)arrayData[index][i];
                        CvInvoke.Line(hist, p1, p2, colors[index], 3);
                        p1.X = p2.X;
                        p1.Y = p2.Y;
                    }
                }
                return hist.Mat;
            }
        }
        private void button37_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            var dhData = getDenseHistogramDataOfImage(chapter4Img);
            var histMat = AddMultiHistograms(dhData);
            imageBox18.Image = histMat;
        }
        //利用查找表反转灰度图像
        private void button38_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            Mat lut = new Mat(1, 256, DepthType.Cv8U, 1);
            byte[] data = new byte[256];
            for(int i=0;i<data.Length;i++)
            {
                data[i] = (byte)(256 - i);
            }
            lut.SetTo(data);
            Mat resultImg = new Mat();
            CvInvoke.LUT(chapter4Img, lut, resultImg);
            imageBox17.Image = resultImg;
        }
        //基于查找表的直方图伸展，图像增强
        private void button39_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            var dhData = getDenseHistogramDataOfImage(chapter4Img);//默认直方图256Bins，像素值方位[0.255]
            RangeF[] minValueAndMaxVlue = new RangeF[3];
            float minValue = 0.01f;//忽略数量少于minValue的箱子,定义数值范围0-1
            if (minValue < 0)
                minValue = 0;
            else if (minValue > 1)
                minValue = 1;
            minValue = chapter4Img.Rows * chapter4Img.Cols * minValue;//计算得到最小箱子
            for(int i=0;i<dhData.Length;i++)
            {
                if(dhData[i]==null)
                {
                    minValueAndMaxVlue[i].Max = minValueAndMaxVlue[i].Min = -1f;//及不存在这个通道的数据
                    continue;
                }
                minValueAndMaxVlue[i].Min = 0f;
                for (;minValueAndMaxVlue[i].Min < dhData[i].GetBinValues().Length; minValueAndMaxVlue[i].Min+=1)
                {
                    if (dhData[i].GetBinValues()[(int)minValueAndMaxVlue[i].Min] > minValue)
                        break;
                }
                minValueAndMaxVlue[i].Max = dhData[i].GetBinValues().Length - 1;
                for(;minValueAndMaxVlue[i].Max>=0;minValueAndMaxVlue[i].Max-=1)
                {
                    if (dhData[i].GetBinValues()[(int)minValueAndMaxVlue[i].Max] > minValue)
                        break;
                }
            }
            var lut = new Image<Bgr, byte>(256, 1);
            List<byte[]> arrayData = new List<byte[]>();
            arrayData.Add(new byte[256]);
            arrayData.Add(new byte[256]);
            arrayData.Add(new byte[256]);
            if (chapter4Img.NumberOfChannels==1)
            {
                for(int i=0;i<256;i++)
                {
                    if (i < minValueAndMaxVlue[0].Min)
                        arrayData[0][i] = 0;
                    else if (i > minValueAndMaxVlue[0].Max)
                        arrayData[0][i] = 255;
                    else
                        arrayData[0][i] = (byte)Math.Round(255.0 * (i - minValueAndMaxVlue[0].Min) / (minValueAndMaxVlue[0].Max - minValueAndMaxVlue[0].Min));
                }
            }
            else//对每个通道进行计算，得到范围
            {
                for(int index=0;index<3;index++)
                {
                    arrayData[index] = new byte[256];
                    for (int i = 0; i < 256; i++)
                    {
                        if (i < minValueAndMaxVlue[index].Min)
                            arrayData[index][i] = 0;
                        else if (i > minValueAndMaxVlue[0].Max)
                            arrayData[index][i] = 255;
                        else
                            arrayData[index][i] = (byte)Math.Round(255.0 * (i - minValueAndMaxVlue[index].Min) / (minValueAndMaxVlue[index].Max - minValueAndMaxVlue[0].Min));
                    }
                }
            }
            for(int i=0;i<256;i++)
            {
                for(int j=0;j<3;j++)
                {
                    lut.Data[0, i, j] = arrayData[j][i];
                }
            }

            Mat resultImg = new Mat();
            if(chapter4Img.NumberOfChannels==1)
            {
                CvInvoke.LUT(chapter4Img, lut.Split()[0].Mat, resultImg);
            }
            else
            {
                CvInvoke.LUT(chapter4Img, lut.Split()[0].Mat, resultImg);
            }
            CvInvoke.NamedWindow("Based on One Channel (Blue)", NamedWindowType.Normal);
            CvInvoke.Imshow("Based on One Channel (Blue)", resultImg);
            //对所有的通道取同样的minValueAndMaxValue范围计算
            arrayData.Add(new byte[256]);//再加一个数组
            int newMinValue = Math.Min((int)Math.Min(minValueAndMaxVlue[0].Min, minValueAndMaxVlue[1].Min), (int)minValueAndMaxVlue[2].Min);
            int newMaxValue= Math.Max((int)Math.Max(minValueAndMaxVlue[0].Max, minValueAndMaxVlue[1].Max), (int)minValueAndMaxVlue[2].Max);
            for(int i=0;i<256;i++)
            {
                if (i < newMinValue)
                    arrayData[3][i] = 0;
                else if (i > newMaxValue)
                    arrayData[3][i] = 255;
                else
                    arrayData[3][i] = (byte)((255.0*(i - newMinValue) / (newMaxValue - newMinValue)));
            }
            var newLut = new Mat(1, 256, DepthType.Cv8U, 1);
            newLut.SetTo(arrayData[3]);
            if(chapter4Img.NumberOfChannels==3)
            {
                CvInvoke.LUT(chapter4Img, newLut, resultImg);
                CvInvoke.NamedWindow("Based on BGR three Channels", NamedWindowType.KeepRatio);
                CvInvoke.Imshow("Based on BGR three Channels", resultImg);
            }
            else
            {
                CvInvoke.LUT(chapter4Img, lut.Split()[0].Mat, resultImg);
                CvInvoke.NamedWindow("Based on One Channel", NamedWindowType.KeepRatio);
                CvInvoke.Imshow("Based on One Channel", resultImg);
            }
        }

        private void button40_Click(object sender, EventArgs e)//直方图均衡，使用opencv命令
        {
            if (chapter4Img.IsEmpty)
                return;
            if(chapter4Img.NumberOfChannels==3)
            {
                var imgs = chapter4Img.ToImage<Bgr, byte>().Split();
                CvInvoke.EqualizeHist(imgs[0], imgs[0]);
                CvInvoke.EqualizeHist(imgs[1], imgs[1]);
                CvInvoke.EqualizeHist(imgs[2], imgs[2]);
                var dstImg = chapter4Img.ToImage<Bgr, byte>();
                for(int i=0;i<dstImg.Rows;i++)
                    for(int j=0;j<dstImg.Cols;j++)
                    {
                        dstImg.Data[i, j, 0] = imgs[0].Data[i, j, 0];
                        dstImg.Data[i, j, 1] = imgs[1].Data[i, j, 0];
                        dstImg.Data[i, j, 2] = imgs[2].Data[i, j, 0];
                    }
                CvInvoke.NamedWindow("Opencv EqualizeHist", NamedWindowType.KeepRatio);
                CvInvoke.Imshow("Opencv EqualizeHist", dstImg);
            }
            else
            {
                var dstImg = chapter4Img.Clone();
                CvInvoke.EqualizeHist(dstImg, dstImg);
                CvInvoke.NamedWindow("Opencv EqualizeHist", NamedWindowType.KeepRatio);
                CvInvoke.Imshow("Opencv EqualizeHist", dstImg);
            }
        }
        //反向投影直方图，基本原理是根据ROI图像直方图信息，获得原始图像中的像素点对应该直方图归一化后的概率，即概率越高，说明该点属于ROI的概率越大。代码中用到了三种，前两种是自己写的，最后一个使用了DenseHistogram类中的反向投影函数。从结果来看，DenseHistogram的方法最优
        private void button41_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            Mat img = new Mat();
            if (chapter4Img.NumberOfChannels != 1)
                CvInvoke.CvtColor(chapter4Img, img, ColorConversion.Bgr2Gray);//若是多通道图像，先转换为灰度图像
            else
                img = chapter4Img.Clone();
            var imgROI = new Mat(img, new Rectangle(100,100,200,200));
            CvInvoke.Imshow("ROI", imgROI);//ROI图像
            var hist = getDenseHistogramDataOfImage(imgROI);//获得ROI区域的直方图信息
            //此时 得到的DenseHistogram数组必然只含有一个对象
            //直接将图像中的像素替换为ROi直方图对应的强度值
            var resultimg2 = img.ToImage<Gray, byte>();
            for(int i=0;i<resultimg2.Rows;i++)
                for(int j=0;j<resultimg2.Cols;j++)
                {
                    resultimg2.Data[i, j, 0] = (byte)(hist[0].GetBinValues()[resultimg2.Data[i, j, 0]]);
                }
            CvInvoke.NamedWindow("backByDIY1", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("backByDIY1", resultimg2);

            //先将ROI的一维直方图归一化，再重复上面的操作，并将得到的数值乘255，使得最终范围还是0-255
            double[] aaa = new double[256];
            for(int i=0;i<256;i++)
            {
                aaa[i] = hist[0].GetBinValues()[i];
            }
            var histData = new Mat(1, 256, DepthType.Cv64F, 1);
            histData.SetTo(aaa);
            CvInvoke.Normalize(histData, histData, 1.0);//归一化
            var normalizedData = histData.ToImage<Gray, double>();
            var resultimg = img.ToImage<Gray, byte>();
            for(int i=0;i<resultimg.Rows;i++)
                for(int j=0;j<resultimg.Cols;j++)
                {
                    resultimg.Data[i, j, 0] = (byte)(255.0 * normalizedData.Data[0, resultimg.Data[i, j, 0], 0]);
                }
            CvInvoke.NamedWindow("backByDIY2", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("backByDIY2", resultimg);
            
            //直接使用DenseHistogram中的backprojection方法
            var resultImg = hist[0].BackProject<byte>(new Image<Gray, byte>[] { img.ToImage<Gray, byte>() });
            CvInvoke.NamedWindow("backByDenseHistogram", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("backByDenseHistogram", resultImg);
        }
        //基于RGB三通道的彩色图像反向投影直方图,分别对三个通道进行search，最后整合成彩色图像
        //需要注意的是，这里的彩色图像是最后根据ROi直方图反向投影得到，所以和原始彩色图像的颜色会有所不同
        private void button42_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            if (chapter4Img.NumberOfChannels != 3)//不是三通道，因为想偷懒
                return;
            var imgs = chapter4Img.ToImage<Bgr, byte>().Split();
            var imgROI = new Mat(chapter4Img, new Rectangle(240, 130, 110, 110));
            CvInvoke.NamedWindow("ROI", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("ROI", imgROI);
            var hist = getDenseHistogramDataOfImage(imgROI);//此时有三个DenseHistogram对象
            var resultImgB = hist[0].BackProject<byte>(new Image<Gray, byte>[] { imgs[0] });
            var resultImgG = hist[1].BackProject<byte>(new Image<Gray, byte>[] { imgs[1] });
            var resultImgR = hist[2].BackProject<byte>(new Image<Gray, byte>[] { imgs[2] });
            CvInvoke.NamedWindow("R", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("R", resultImgR);
            CvInvoke.NamedWindow("G", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("G", resultImgG);
            CvInvoke.NamedWindow("B", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("B", resultImgB);
            var resultImg = chapter4Img.ToImage<Bgr, byte>();
            for(int i=0;i<resultImg.Rows;i++)
                for(int j=0;j<resultImg.Cols;j++)
                {
                    resultImg.Data[i, j, 0] = resultImgB.Data[i, j, 0];
                    resultImg.Data[i, j, 1] = resultImgG.Data[i, j, 0];
                    resultImg.Data[i, j, 2] = resultImgR.Data[i, j, 0];
                }
            CvInvoke.NamedWindow("backByDenseHistogram", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("backByDenseHistogram", resultImg);
        }

        private void button43_Click(object sender, EventArgs e)
        {
            Mat baseMat = new Mat();
            Mat detectedMat = new Mat();
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                baseMat = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyColor);//获取基准图像,该图像用来获得狒狒脸部ROI
            if (baseMat.IsEmpty | baseMat.NumberOfChannels != 3)
                return;
            var rect = new Rectangle(113, 252, 35, 40);
            var tempImg = baseMat.Clone();
            CvInvoke.NamedWindow("baseImage", NamedWindowType.KeepRatio);
            CvInvoke.Rectangle(tempImg, rect, new MCvScalar(0, 0, 255), 2);
            CvInvoke.Imshow("baseImage", tempImg);//显示基准图像，并标出ROI区域

            var imgROI = new Mat(baseMat, rect);//狒狒脸部ROI
            //屏蔽饱和度过低的像素,得到掩码mask
            int minSat = 65;
            var hsvROI = new Mat();
            CvInvoke.CvtColor(imgROI, hsvROI, ColorConversion.Bgr2Hsv);
            var hsvROIImg = hsvROI.ToImage<Hsv, byte>();
            var mask = new Mat();
            CvInvoke.Threshold(hsvROIImg.Split()[1], mask, minSat, 255, ThresholdType.Binary);
            //得到ROI色调直方图，mask中的像素没有参与计算 
            DenseHistogram hist = new DenseHistogram(181, new RangeF(0f, 180.1f));
            hist.Calculate<byte>(new Image<Gray, byte>[] { hsvROIImg.Split()[0] }, false, mask.ToImage<Gray, byte>());
            //获取将要检测的图像，并对HSV图像中的色调图像反投影
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
                detectedMat = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyColor);//获取图像
            if (detectedMat.IsEmpty | detectedMat.NumberOfChannels != 3)
                return;
            var hsvMat = new Mat();
            CvInvoke.CvtColor(detectedMat, hsvMat, ColorConversion.Bgr2Hsv);//获取HSV数据
            var resultImg = hist.BackProject<byte>(new Image<Gray, byte>[] { hsvMat.ToImage<Hsv, byte>().Split()[0] });
            var criteria = new MCvTermCriteria(1000, 0.01);
            CvInvoke.MeanShift(resultImg, ref rect, criteria);//均值偏移，计算得到脸部区域
            tempImg = detectedMat.Clone();
            CvInvoke.Rectangle(tempImg, rect, new MCvScalar(255, 0, 0), 2);
            CvInvoke.NamedWindow("detectedImage", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("detectedImage", tempImg);
        }

        private void button44_Click(object sender, EventArgs e)
        {
            Mat baseImage = new Mat();
            Mat inputImage = new Mat();
            string baseImageName="", inputImageName="";
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
            {
                baseImage = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
                baseImageName = chapter1OFD.SafeFileName;
            }    
            if (chapter1OFD.ShowDialog() == DialogResult.OK)
            {
                inputImage = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);
                inputImageName = chapter1OFD.SafeFileName;
            }
            if (baseImage.IsEmpty | inputImage.IsEmpty | baseImage.NumberOfChannels != 3 | inputImage.NumberOfChannels != 3 | baseImage.Size != inputImage.Size | baseImage.Depth != inputImage.Depth)
                return;
            ImageComparator ic = new ImageComparator();
            ic.setBaseImage(baseImage);
            ic.setInputImage(inputImage);
            ic.setNumberOfBins(8);
            double iii = ic.calculateDifference();
            int ii = 0;
            textBox3.Text += baseImageName+" VS "+inputImageName+" : " + iii+Environment.NewLine;
        }

        private void button45_Click(object sender, EventArgs e)
        {
            if (chapter4Img.IsEmpty)
                return;
            Mat img = new Mat();
            if (chapter4Img.NumberOfChannels == 3)
                CvInvoke.CvtColor(chapter4Img, img, ColorConversion.Bgr2Gray);
            else
                img = chapter4Img.Clone();
            Mat integralImg = new Mat();
            CvInvoke.Integral(img, integralImg);
            imageBox17.Image = integralImg;//此时生成的积分图像大小为(x+1,y+1),在这种情况下，SAT(0,x)=SAT(x,0)=SAT(0,0)=0
            var imgData = img.ToImage<Gray, byte>();
            var integralImgData = integralImg.ToImage<Gray, float>();
            int threshold = 10;
            int halfSize = 10;
            int blockSize = 2 * halfSize + 1;
            for(int i=halfSize+1;i<img.Rows-halfSize;i++)
                for(int j=halfSize+1;j<img.Cols-halfSize;j++)
                {
                    int sum = (int)(integralImgData.Data[i + halfSize + 1, j + halfSize + 1, 0] + integralImgData.Data[i - halfSize, j - halfSize, 0] - integralImgData.Data[i + halfSize + 1, j - halfSize, 0] - integralImgData.Data[i - halfSize, j + halfSize + 1, 0]);
                    if (imgData.Data[i, j, 0] < (sum/(blockSize*blockSize) - threshold))
                        imgData.Data[i, j, 0] = 0;
                    else
                        imgData.Data[i, j, 0] = 255;
                }
            imageBox17.Image = imgData;
            //下面部分代码使用opencv自带的自适应阈值分割方法
            Mat opencvMat = new Mat();
            CvInvoke.AdaptiveThreshold(img, opencvMat, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, blockSize, threshold);
            CvInvoke.NamedWindow("OpenCV-AdaptiveThreshold", NamedWindowType.KeepRatio);
            CvInvoke.Imshow("OpenCV-AdaptiveThreshold", opencvMat);
        }
    }









    //定义一个用于基于直方图比较的图像相似度计算类
    public class ImageComparator
{
    private Mat baseImg;
    private Mat inputImg;
    int nBins;//每个颜色通道使用的箱子数量
    public ImageComparator()
    {
        nBins = 8;//默认8个箱子
    }
    public void setNumberOfBins(int n)
    {
        nBins = n;
    }
    public void setBaseImage(Mat img)
    {
        baseImg = img;
    }
    public void setInputImage(Mat img)
    {
        inputImg = img;
    }
    public double calculateDifference()//简化代码量，直接默认输入图像都是BGR三通道彩色图像
    {
        DenseHistogram[] histogramOfBaseImage = new DenseHistogram[3];
        DenseHistogram[] histogramOfInputImage = new DenseHistogram[3];
        for(int i=0;i<3;i++)
        {
            histogramOfBaseImage[i] = new DenseHistogram(nBins, new RangeF(0f, 255.1f));
            histogramOfBaseImage[i].Calculate<byte>(new Image<Gray, byte>[] { baseImg.ToImage<Bgr, byte>().Split()[i] }, false, null);
            histogramOfInputImage[i] = new DenseHistogram(nBins, new RangeF(0f, 255.1f));
            histogramOfInputImage[i].Calculate<byte>(new Image<Gray, byte>[] { inputImg.ToImage<Bgr, byte>().Split()[i] }, false, null);
        }
        Image<Bgr, float> histOfBaseImg = new Image<Bgr, float>(nBins, 1);
        Image<Bgr, float> histOfInputImg = new Image<Bgr, float>(nBins, 1);
        for(int i=0;i<3;i++)
            for(int j=0;j<nBins;j++)
            {
                histOfBaseImg.Data[0, j, i] = (float)histogramOfBaseImage[i].GetBinValues()[j];
                histOfInputImg.Data[0, j, i] = (float)histogramOfInputImage[i].GetBinValues()[j];
            }
        return CvInvoke.CompareHist(histOfBaseImg, histOfInputImg, HistogramCompMethod.Bhattacharyya);
    }
}




    //以下是用于颜色检测的类基于RGB
    public class ColorDetector
    {
        private int maxDist;
        private MCvScalar targetColor;
        private Mat result=new Mat();
        private void setTarget(int b,int g,int r)
        {

            targetColor.V0 = b;
            targetColor.V1 = g;
            targetColor.V2 = r;
        }
        public void setTargetColor(byte blue,byte green,byte red)
        {
            setTarget(blue, green, red);
        }
        public void setTargetColor(Color c)
        {
            setTarget(c.B, c.G, c.R);
        }
        int getColorDistance(Color c1,Color c2)
        {
            return (int)Math.Sqrt(Math.Pow((c1.B - c2.B), 2) + Math.Pow((c1.G - c2.G), 2) + Math.Pow((c1.R - c2.R), 2));
        }
        int getDistanceToTargetColor(Color c)
        {
            Color tempC;
            tempC = Color.FromArgb((int)targetColor.V2, (int)targetColor.V1, (int)targetColor.V0);
            var ds=getColorDistance(c, tempC);
            ////以下是采用opencv的norm函数进行计算,仅仅为了说明一下，故将其注释掉
            //Mat temp = new Mat(3, 1, DepthType.Cv64F, 1);
            //var tempImg = temp.ToImage<Gray,float>();
            //tempImg.Data[0, 0, 0] = c.R - tempC.R;
            //tempImg.Data[1, 0, 0] = c.G - tempC.G;
            //tempImg.Data[2, 0, 0] = c.B - tempC.B;
            //var opencvDs = CvInvoke.Norm(tempImg);
            ////over
            return (int)ds;
        }
        public ColorDetector()
        {
            maxDist = 100;
            setTarget(0, 0, 0);
        }
        void setColorDistanceThreshold(int distance)
        {
            if (distance < 0)
                distance = 0;
            maxDist = distance;
        }
        int getColorDistanceThreshold()
        {
            return maxDist;
        }
        public Mat process(Mat inImg)
        {
            result.Create(inImg.Rows, inImg.Cols, DepthType.Cv8U, 1);
            var tempImg = result.ToImage<Gray, byte>();
            var tempImg2 = inImg.ToImage<Bgr, byte>();
            for(int i=0;i<tempImg2.Rows;i++)
                for(int j=0;j<tempImg2.Cols;j++)
                {
                    if(getDistanceToTargetColor(Color.FromArgb(tempImg2.Data[i,j,2], tempImg2.Data[i, j, 1], tempImg2.Data[i, j, 0]))<maxDist)
                    {
                        tempImg.Data[i, j, 0] = 255;
                    }
                    else
                    {
                        tempImg.Data[i, j, 0] = 0;
                    }
                }
            tempImg.Mat.CopyTo(result);
            return result;
        }
    }
}
